package leo.weixin.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baidu.aip.ocr.AipOcr;
import leo.weixin.common.Const;
import leo.weixin.config.ApiConfig;
import leo.weixin.entity.*;
import leo.weixin.entity.message.BaseMessage;
import leo.weixin.entity.message.NewsMessage;
import leo.weixin.entity.message.TextMessage;
import leo.weixin.service.IEventService;
import leo.weixin.service.IWxService;
import leo.weixin.util.BeanUtil;
import leo.weixin.util.FileUtil;
import leo.weixin.util.IptkRobot;
import leo.weixin.util.RestTemplateUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.HttpsURLConnection;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Service("iWxService")
public class WxServiceImpl implements IWxService {
    @Autowired
    private ApiConfig config;
    @Autowired
    private AipOcr ocrClient;
    @Autowired
    private IEventService iEventService;
    private static AccessToken at;
    private static final String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    /**
     * 从微信获取token
     * 参数	说明
     * access_token	获取到的凭证
     * expires_in	凭证有效时间，单位：秒
     *
     */
    private void getToken(){
        String url = GET_TOKEN_URL.replace("APPID",config.getWxPubAppId()).replace("APPSECRET",config.getWxPubSecret());
        String result = RestTemplateUtil.get(url);
        JSONObject jsonObject = JSON.parseObject(result);
        at = new AccessToken(jsonObject.getString("access_token"),jsonObject.getString("expires_in"));
    }
    @Override
    public String getAccessToken(){
        if (at == null || at.isExpired()){
            getToken();
        }
        return at.getAccessToken();
    }

    /**
     * 请原样返回echostr参数内容，则接入生效，成为开发者成功，否则接入失败。加密/校验流程如下：
     * 1）将token、timestamp、nonce三个参数进行字典序排序
     * 2）将三个参数字符串拼接成一个字符串进行sha1加密
     * 3）开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    @Override
    public String check(String signature, String timestamp, String nonce, String echostr) {
        String[] arr = {config.getWxPubToken(),timestamp,nonce};
        Arrays.sort(arr);
        String str = arr[0] + arr[1] + arr[2];
        return this.sha1(str).equals(signature) ? echostr : null;
    }



    @Override
    public String deal(InputStream is) {
        Map<String, String> map = this.parseRequest(is);
        //System.out.println("接收到:"+map);   //todo 删除
        String msgType =  map.get(Const.RequestParamEnum.MSG_TYPE);
        BaseMessage message = null ;
        switch (msgType) {
            case Const.MsgTypeEnum.TEXT :
                message = dealText(map);
                break;
            case Const.MsgTypeEnum.IMAGE :
                message = imgRecognize(map);
                break;
            case Const.MsgTypeEnum.LINK :

                break;
            case Const.MsgTypeEnum.LOCATION :

                break;
            case Const.MsgTypeEnum.VIDEO :

                break;
            case Const.MsgTypeEnum.SHORT_VIDEO :

                break;
            case Const.MsgTypeEnum.VOICE :

                break;
            case Const.MsgTypeEnum.EVENT :
                message = iEventService.dealEvent(map);
            default :
                break;
        }

        return createMessage(message);
    }
    @Override
    public String createMessage(BaseMessage msg){
        return BeanUtil.beanToXml(msg);
    }

    @Override
    public String addMedia(MultipartFile file) {
        File targetFile = FileUtil.multipartFileToFile(file);
        //永久素材 https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE
        //零时素材"https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
        String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE";
        url = url.replace("ACCESS_TOKEN", getAccessToken())
                .replace("TYPE", "image");   // todo 这个参数需要由用户控制  type
        String result = RestTemplateUtil.upload(url,targetFile);
        targetFile.delete();
        return result;
    }

    @Override
    public String getMedia(String mediaId) {
        String url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
        url = url.replace("ACCESS_TOKEN",getAccessToken())
                .replace("MEDIA_ID","0E7cAZ3LEALBLUXa-LRMVzhylf7_IDn1qMaz9WOTTbY");
        String res = RestTemplateUtil.get(url);
        System.out.println(res);
        return null;
    }

    @Override
    public String addMaterial(Object material) {
        //http请求方式: POST，https协议
        //https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN
        String url = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN";
        url = url.replace("ACCESS_TOKEN",getAccessToken());
        //处理永久素材对象material
        Map<String,Object> params = new HashMap<>();
        List<leo.weixin.entity.material.Article> articles = new ArrayList<>();
        leo.weixin.entity.material.Article article = leo.weixin.entity.material.Article.builder()
                .title("title")
                .content("content")
                .contentSourceUrl("contentUrl")
                .showCoverPic(false)
                .thumbMediaId("0E7cAZ3LEALBLUXa-LRMVzhylf7_IDn1qMaz9WOTTbY")
                .build()
                .setAuthor("author")
                .setDigest("digest")
                .setOnlyFansCanComment(true)
                .setNeedOpenComment(true);
        articles.add(article);
        params.put("articles",articles);
        System.out.println(JSON.toJSONString(params,true));
        String res = RestTemplateUtil.post(url,JSON.toJSONString(params));
        System.out.println(res);
        return null;
    }

    @Override
    public String getQrCode() {
        /**
         * http请求方式: POST
         * URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
         * POST数据格式：json
         * "expire_seconds": 604800 秒 永久二维码除去这个参数 过期时间
         * POST数据例子：{"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
         * 参数	说明
         * expire_seconds	该二维码有效时间，以秒为单位。 最大不超过2592000（即30天），此字段如果不填，则默认有效期为30秒。
         * action_name	二维码类型，QR_SCENE为临时的整型参数值，QR_STR_SCENE为临时的字符串参数值，QR_LIMIT_SCENE为永久的整型参数值，QR_LIMIT_STR_SCENE为永久的字符串参数值
         * action_info	二维码详细信息
         * scene_id	场景值ID，临时二维码时为32位非0整型，永久二维码时最大值为100000（目前参数只支持1--100000）
         * scene_str	场景值ID（字符串形式的ID），字符串类型，长度限制为1到64
         */
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN";
        url = url.replace("TOKEN",getAccessToken());
        // 数据准备
        Map<String,Object> scene = new HashMap<>();
        scene.put("scene_id",1+new Random().nextInt(100000));

        Map<String,Object> action_info = new HashMap<>();
        action_info.put("scene",scene);

        Map<String,Object> params = new HashMap<>();
        params.put("expire_seconds",20);  //10分钟
        params.put("action_name","QR_SCENE");
        params.put("action_info",action_info);
        String result = RestTemplateUtil.post(url,JSON.toJSONString(params));
        result = JSON.parseObject(result).getString("ticket");
        return result;
    }


    /**
     * 文本消息的处理
     * @param map
     * @return
     */
    private BaseMessage dealText(Map<String, String> map) {
        String content = map.get(Const.RequestParamEnum.CONTENT);
        getAccessToken();
        // 使用content....  查数据库  ,,  百度搜索 ,, 其他
        if (content.equals("图文")) {
            List<Article> articles = new ArrayList<>();
            Article article = new Article();
            article.setTitle("怎么实现动态代理？").setDescription("描述信息")
                    .setUrl("http://www.baidu.com")
                    .setPicUrl("http://mmbiz.qpic.cn/mmbiz_jpg/iatcfA8XJic6WSwiaHDdXpx29NVxu6a5BqicNU7PLqoDBNwoWAIakc3WqTcaLSukbVhqOkibniboiakZ2iblVEyJO4NUgA/0");
            articles.add(article);
            return new NewsMessage(map,articles,1);
        }
        content = IptkRobot.sendTextMessage(content) ;
        return new TextMessage(map,content);
    }

    /**
     * sha1加密
     * @param src
     * @return
     */
    private String sha1(String src){
        try {
            MessageDigest md = MessageDigest.getInstance("sha1");
            byte[] digest = md.digest(src.getBytes());
            // 加密结果处理
            StringBuilder result = new StringBuilder();
            char[] chs = "0123456789abcdef".toCharArray();
            for (byte b : digest) {
                result.append(chs[(b>>4) & 15]);
                result.append(chs[b & 15]);
            }
            return result.toString();
        } catch (NoSuchAlgorithmException e) {

        }
        return null ;
    }

    /**
     * 图像识别
     * @param
     * @return
     */
    private BaseMessage imgRecognize(Map<String, String> map){
        HashMap<String, String> options = new HashMap<String, String>();
        options.put("detect_direction", "true");
        options.put("detect_language", "true");
        // 网络图片文字识别, 图片参数为远程url图片
        org.json.JSONObject jsonObject = ocrClient.webImageUrl(map.get("PicUrl"), options);
       // System.out.println(jsonObject.toString(2));
        JSONArray array = jsonObject.getJSONArray("words_result");
        Iterator<Object> it = array.iterator();
        //int count = 1 ;
        StringBuilder sb = new StringBuilder();
        while (it.hasNext()){
            jsonObject = (org.json.JSONObject) it.next();
            sb.append(jsonObject.get("words")).append("  ");
            //count = count == 3 ? 1 : count + 1;
        }
        return new TextMessage(map,sb.toString());
    }

    /**
     * 将xml文档解析为map
     * @param is
     * @return
     */
    private Map<String,String> parseRequest(InputStream is){
        Map<String,String> map = new HashMap<>();
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(is);//获取文档对象
            Element root = document.getRootElement();
            List<Element> elements = root.elements();
            for (Element element : elements) {
                map.put(element.getName(), element.getStringValue());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map ;
    }
}
